package uk.ac.glasgow.demosocs.impl.electionTypes;

import java.io.Serializable;
import java.util.Hashtable;
import java.util.Scanner;
import java.util.Set;

import uk.ac.glasgow.demosocs.Candidate;
import uk.ac.glasgow.demosocs.ElectionResult;
import uk.ac.glasgow.demosocs.Option;
import uk.ac.glasgow.demosocs.Vote;
import uk.ac.glasgow.demosocs.impl.ElectionResultImpl;
import uk.ac.glasgow.demosocs.impl.OneOfNVoteStub;
import uk.ac.glasgow.demosocs.impl.ReferendumResultImpl;
import uk.ac.glasgow.demosocs.impl.ReferendumVoteImpl;

/**
 * 
 * This represents a referendum. It contains the question set by the admin.
 *
 */
public class Referendum extends ElectoralSystem implements Serializable {

	private static final long serialVersionUID = 1L;
	private Hashtable<String, Integer> options = new Hashtable<String, Integer>(); // CandidateGUID,
																					// number
																					// votes

	private Hashtable<String, String> votedFor = new Hashtable<String, String>(); // userID,
																					// option
																					// voted
																					// for

	private String question;
	private Set<Candidate> candidates;


	/**
	 * Constructor to create a new instance of referendum.
	 * @param candidates - A list of candidates for the election.
	 */
	public Referendum(Set<Candidate> candidates) {
		this.candidates = candidates;
		options.put("yes", 0);
		options.put("no", 0);
		System.out.println("Enter the question for the referendum");
		Scanner scan = new Scanner(System.in);
		String q = scan.nextLine();
		question = q;
	}

	@Override
	public ElectionResult getElectionResult() {
		String result = "";
		if (options.get("yes") > options.get("no")) {
			result = "yes";
		} else if (options.get("no") > options.get("yes"))
			result = "no";
		else
			result = "tie";

		ReferendumResultImpl r = new ReferendumResultImpl(result);
		return new ElectionResultImpl(r);
	}

	public static String getFactoryName() {
		return "Referendum";
	}

	@Override
	public String getName() {
		return getFactoryName();
	}

	@Override
	public String toString() {
		return "Referendum Factory";
	}

	/**
	 * Casts a vote for a referendum.
	 * @param v - Abstract representation of vote. The vote should either contain
	 * yes or no.
	 */
	@Override
	public void vote(Vote v) {

		ReferendumVoteImpl referendumVote = ((ReferendumVoteImpl) v);
		String option = referendumVote.getOption();
		if (!option.equals("yes")) {
			if (!option.equals("no")) {
				System.out.println("Vote cast must be 'yes' or 'no'");
				return;
			}
		}
		String userId = referendumVote.getVotedBy();

		// here is not doing the comparison correctly

		if (option.equals("yes") || option.equals("no")) {
			// New user voting for an option
			if (!votedFor.containsKey(userId)) {
				int num = options.get(option);
				options.put(option, ++num);
				votedFor.put(userId, option);
			}

			// Existing user is voting again
			// need to decrement their old vote.
			else {
				String oldOption = votedFor.get(userId);
				if (oldOption.equals(option)){
					System.out.println("You have voted for the same option");
					return;
				}
				int oldOptionNum = options.get(oldOption);
				int newOptionNum = options.get(option);
				options.put(oldOption, --oldOptionNum);
				options.put(option, ++newOptionNum);
				votedFor.put(userId, option);

			}
			System.out.println("Referendum Vote has been casted");
		} else {
			System.out.println("Invalid option");
			return;
		}
	}
	
	public String getQuestion() {
		return question;
	}

	public void setQuestion(String question) {
		this.question = question;
	}

}
